﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace SoldiHive.Infrustructure.Extensions
{
	public static class DateTimeExtensions
	{
		public static bool IsFederalHoliday(this DateTime me)
		{
			var schedule = new UnitedStatesHolidaySchedule(UnitedStatesHolidayScheduleTypes.Federal, me.Year);
			var holidays = schedule.GetHolidays();

			return holidays.Any(p => p.Year == me.Year && p.Month == me.Month && p.Day == me.Day);
		}

		public static bool IsStockMarketHoliday(this DateTime me)
		{
			var schedule = new UnitedStatesHolidaySchedule(UnitedStatesHolidayScheduleTypes.StockMarket, me.Year);
			var holidays = schedule.GetHolidays();

			return holidays.Any(p => p.Date == me.Date);
		}

		public static bool IsBusinessDay(this DateTime me)
		{
			return !me.IsStockMarketHoliday() && !me.IsWeekend();
		}

		public static IList<DateTime> BusinessDatesBefore(this DateTime me, DateTime end)
		{
			var bussinessDates = new List<DateTime>();
			var date = me;

			while (date <= end)
			{
				if (date.IsBusinessDay())
				{
					bussinessDates.Add(date);
				}
				date = date.AddDays(1);
			}

			return bussinessDates;
		}

		public static IList<DateTime> GetNeighbouringBusinessDates(this DateTime me, int beforeCount, int afterCount)
		{
			var date = me;
			while (!date.IsBusinessDay())
			{
				date = date.AddDays(1);
			}

			var neighbouringDates = new List<DateTime>();
			
			var previousNeighbouringDate = date.AddDays(-1);
			while (neighbouringDates.Count < beforeCount)
			{
				if (previousNeighbouringDate.IsBusinessDay())
				{
					neighbouringDates.Insert(0, previousNeighbouringDate);
				}

				previousNeighbouringDate = previousNeighbouringDate.AddDays(-1);
			}

			neighbouringDates.Add(date);

			var followingNeighbouringDate = date.AddDays(1);
			while (neighbouringDates.Count < beforeCount + afterCount + 1)
			{
				if (followingNeighbouringDate.IsBusinessDay())
				{
					neighbouringDates.Add(followingNeighbouringDate);
				}

				followingNeighbouringDate = followingNeighbouringDate.AddDays(1);
			}

			return neighbouringDates;
		}

		public static DateTime GetClosestBusinessDate(this DateTime me)
		{
			if (me.IsBusinessDay())
			{
				return me;
			}

			var closestBusinessDate = me.AddDays(1);
			while (!closestBusinessDate.IsBusinessDay())
			{
				closestBusinessDate = closestBusinessDate.AddDays(1);
			}

			return closestBusinessDate;
		}
	}
}
